#include <sys/types.h>
#include <sys/time.h>
#include <sys/ioctl.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>

#include <sys/socket.h>
#include <netinet/in.h>


int main()
{
	int server_sockfd,client_sockfd;
	int server_len,client_len;
	struct sockaddr_in server_addr;
	struct sockaddr_in client_addr;
	int result;
	fd_set readfds, testfds;
	/*
	 * 定义一些变量，服务器和客户端的套接字描述符，地址结构体和长度
	 * 两个fd_set的集合，inputs和testfds；
	 * 一个result的返回值。
	 * */

	server_sockfd = socket(AF_INET, SOCK_STREAM, 0);

	server_addr.sin_family = AF_INET;
	server_addr.sin_addr.s_addr = htonl(INADDR_ANY);
	server_addr.sin_port = htons(3366);
	server_len = sizeof(server_addr);

	if (bind(server_sockfd, (struct sockaddr *)&server_addr, server_len) != 0) {
		perror("bind");
		exit(1);
	}

	listen(server_sockfd,5);
	/*
	 * 创建套接字，设置套接字，关联套接字到本地文件，建立队列,等待客户端的连接
	 *
	 * */

	FD_ZERO(&readfds);
	FD_SET(server_sockfd,&readfds);//读取标准输入，文件描述符0

	while (1) {
		char ch;
		int fd;
		int nread;

		testfds = readfds;

		printf("server waiting\n");
		result = select(FD_SETSIZE, &testfds, NULL,NULL,NULL);//FD_SETSIZE是什么玩意？集合的一个宏？？
		/*
		 * 开始等待客户和请求的到来。因为你给timout的参数为空，所有select调用将不会发送超时,如果没有事情可做，让一直堵塞。如果返回值小于1，则出错。
		 * */
		if (result < 1) {
			perror("select");
			exit(1);
		}

		for (fd = 0; fd < FD_SETSIZE; fd++) {
			if (FD_ISSET(fd,&testfds)) {
				if (fd == server_sockfd) {
					client_len = sizeof(client_addr);
					client_sockfd = accept(server_sockfd,
							(struct sockaddr *)&client_addr,&client_len);
					FD_SET(client_sockfd,&readfds);
					printf("adding client on fd %d\n", client_sockfd);
				}
				else {
					ioctl(fd, FIONREAD, &nread)	;

					if (nread == 0) {
						close(fd);
						FD_CLR(fd,&readfds);
						printf("removing client on fd %d\n",fd);//nread == 0,就能表明客户端关闭的连接。??

					}
					else {
						read(fd, &ch ,1); 
							sleep(5);
							printf("serving client on fd %d\n", fd);
							ch++;
							write(fd,&ch,1);
					}
				}
			}
		}
		/*
		 * 遍历套接字集合，如果一个套接字属于当前的集合（这个套接字之前已经通过FD_SET添加到集合中，在select函数中被检测，如果有变化会返回）
			 * 如果这个集合是服务器的套接字，则表明一个新的连接被请求，则使用accept来响应这个连接，并将返回的套接字描述符添加到当前集合中，如果不是表明是客户端的套接字读写请求，使用ioctl来控制文件描述符来进行读写。
				 * 如果nread的值为0则表示有客户端断开连接，（**为什么不是表示没有数据呢？**），从集合中删除套接字。
				 * 不为0则读写套接字。
		 * */

	}//---while loop endof
}
